package org.jetlinks.pro.assets.impl.entity;

import lombok.Getter;
import lombok.Setter;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.collections4.CollectionUtils;
import org.hswebframework.ezorm.rdb.mapping.annotation.DefaultValue;
import org.hswebframework.ezorm.rdb.mapping.annotation.Upsert;
import org.hswebframework.web.api.crud.entity.GenericEntity;
import org.hswebframework.web.authorization.simple.SimpleDimensionType;
import org.hswebframework.web.crud.generator.Generators;
import org.hswebframework.web.validator.ValidatorUtils;
import org.jetlinks.pro.assets.*;

import javax.persistence.Column;
import javax.persistence.Index;
import javax.persistence.Table;
import java.util.ArrayList;
import java.util.List;

@Table(name = "s_dimension_assets_bind", indexes = {
    @Index(name = "idx_dm_assets_tkey", columnList = "target_key"),
    @Index(name = "idx_dm_assets_atidtkey", columnList = "asset_type,asset_id,target_key")
})
@Getter
@Setter
public class DimensionAssetBindingEntity extends GenericEntity<String> {
    //维度类型
    @Column(length = 32, updatable = false, nullable = false)
    private String targetType;

    //维度ID
    @Column(length = 64, updatable = false, nullable = false)
    private String targetId;

    //维度Key: md5(targetType+targetId) 用于查询
    @Column(length = 32, updatable = false, nullable = false)
    private String targetKey;

    //资产类型
    @Column(length = 32, updatable = false, nullable = false)
    private String assetType;

    //资产ID
    @Column(length = 64, updatable = false, nullable = false)
    private String assetId;

    //与资产关系,首次绑定时关联
    @Column(length = 64, updatable = false)
    private String relation;

    //权限
    @Column(nullable = false)
    @DefaultValue("0")
    @Upsert(insertOnly = true)//upsert时,不能修改此值,防止分配资产时被覆盖.
    private Long permission;

    @Column
    @DefaultValue(generator = Generators.CURRENT_TIME)
    private Long updateTime;

    public static List<DimensionAssetBindingEntity> of(AssetBindRequest request) {
        ValidatorUtils.tryValidate(request);

        List<DimensionAssetBindingEntity> list = new ArrayList<>();
        for (String assetId : request.getAssetIdList()) {
            DimensionAssetBindingEntity entity = new DimensionAssetBindingEntity();
            entity.setAssetId(assetId);
            entity.setAssetType(request.getAssetType());
            entity.setTargetId(request.getTargetId());
            entity.setTargetType(request.getTargetType());
            AssetType assetType = AssetType.of(entity.getAssetType());

            if (request.isAllPermission()) {
                entity.setPermission(assetType.createAllPermission());
            } else if (CollectionUtils.isNotEmpty(request.getPermission())) {
                entity.setPermission(assetType.createPermission(assetType.getPermissions(request.getPermission())));
            }

            entity.setRelation(request.getRelation());
            entity.setUpdateTime(System.currentTimeMillis());
            entity.generateId();
            entity.generateTargetKey();
            list.add(entity);
        }

        return list;
    }

    public void generateTargetKey() {
        setTargetKey(generateKey(targetType, targetId));
    }

    public String generateId() {
        setId(generateId(targetType, targetId, assetType, assetId));
        return getId();
    }

    public static String generateKey(String... strings) {
        return DigestUtils.md5Hex(String.join("|", strings));
    }

    public static String generateId(String targetType,
                                    String targetId,
                                    String assetType,
                                    String assetId) {
        return DigestUtils.md5Hex(String.format("%s|%s|%s|%s", targetType, targetId, assetType, assetId));
    }

    public AssetBinding toBinding() {
        SimpleAssetBinding binding = new SimpleAssetBinding();
        binding.setAssetType(AssetType.of(assetType));
        binding.setPermissionValue(permission == null ? 0 : permission);
        binding.setAssetId(assetId);
        binding.setRelation(relation);
        binding.setTargetType(SimpleDimensionType.of(targetType));
        binding.setTargetId(targetId);
        return binding;
    }
}
